package org.bundlemaker.core.ui.editor.dsm.widget;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Observable;
import java.util.Observer;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.matrix.Matrix;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.sidemarker.HorizontalSideMarker;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.sidemarker.VerticalSideMarker;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.util.BoxSize;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.util.DsmUtils;
import org.bundlemaker.core.ui.editor.dsm.widget.internal.zoom.ZoomableScrollPane;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LayoutListener;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.ScrollPane;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class DsmViewWidget extends Canvas implements Observer {
/** - */
private float _zoom = 1.0f;
/** the content provider */
private IDsmContentProvider _dsmContentProvider;
/** - */
private IDsmColorScheme _colorScheme;
/** - */
private ILabelProvider _artifactLabelProvider;
/** - */
private ILabelProvider _dependencyLabelProvider;
/** the main figure */
private Figure _mainFigure;
private ZoomableScrollPane _zoomableScrollpane;
private ZoomableScrollPane _zoomableScrollpaneVerticalBar;
private ZoomableScrollPane _zoomableScrollpaneHorizontalBar;
/** - */
private Matrix _matrixFigure;
private VerticalSideMarker _verticalListFigure;
private HorizontalSideMarker _horizontalListFigure;
private int _horizontalFigureHeight = 8;
private int _verticalFigureWidth = -1;
private int _x;
private int _y;
private boolean _drawToolTip = false;
private String[] _nodesAsStrings;
private String[][] _dependenciesAsStrings;
/**
* <p>
* Creates a new instance of type {@link DsmViewWidget}.
* </p>
*
* @param contentProvider
* @param canvas
*/
public DsmViewWidget(IDsmContentProvider contentProvider, ILabelProvider artifactLabelProvider,
ILabelProvider dependencyLabelProvider, Composite parent) {
super(parent, SWT.NO_REDRAW_RESIZE);
// assert not null
Assert.isNotNull(contentProvider);
Assert.isNotNull(parent);
Assert.isNotNull(artifactLabelProvider);
Assert.isNotNull(dependencyLabelProvider);
// set model and canvas
this._dsmContentProvider = contentProvider;
//
_artifactLabelProvider = artifactLabelProvider;
_dependencyLabelProvider = dependencyLabelProvider;
// set this view as an observer
this._dsmContentProvider.addObserver(this);
// init
init();
}
/**
* {@inheritDoc}
*/
@Override
public void update(Observable o, Object arg) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
_mainFigure.repaint();
}
});
}
public void setZoom(float value) {
// float z = (value + 10) * 0.02f;
_zoomableScrollpane.setZoom(value);
_zoomableScrollpaneVerticalBar.setZoom(value);
_zoomableScrollpaneHorizontalBar.setZoom(value);
_zoom = value;
//
// _mainFigure.repaint();
}
/**
* <p>
* </p>
*
* @return the zoom
*/
public float getZoom() {
return _zoom;
}
public void setModel(IDsmContentProvider contentProvider) {
if (_dsmContentProvider != null) {
_dsmContentProvider.deleteObserver(this);
}
_nodesAsStrings = null;
_dependenciesAsStrings = null;
_dsmContentProvider = contentProvider;
_matrixFigure.setModel(contentProvider);
_verticalListFigure.setModel(contentProvider);
_horizontalListFigure.setModel(contentProvider);
_verticalFigureWidth = getTextExtend(_matrixFigure, _zoomableScrollpane);
_mainFigure.revalidate();
_mainFigure.repaint();
}
public void addMatrixListener(IMatrixListener listener) {
_matrixFigure.addMatrixListener(listener);
}
public void removeMatrixLIstener(IMatrixListener listener) {
_matrixFigure.removeMatrixLIstener(listener);
}
public String[] getNodesAsStrings() {
if (_nodesAsStrings == null) {
_nodesAsStrings = new String[_dsmContentProvider.getNodes().length];
for (int i = 0; i < _dsmContentProvider.getNodes().length; i++) {
_nodesAsStrings[i] = _artifactLabelProvider.getText(_dsmContentProvider.getNodes()[i]);
}
}
//
return _nodesAsStrings;
}
public String[][] getDependenciesAsStrings() {
if (_dependenciesAsStrings == null) {
_dependenciesAsStrings = new String[_dsmContentProvider.getNodes().length][_dsmContentProvider.getNodes().length];
for (int i = 0; i < _dependenciesAsStrings.length; i++) {
for (int j = 0; j < _dependenciesAsStrings.length; j++) {
if (_dsmContentProvider.getDependencies()[i][j] != null) {
_dependenciesAsStrings[i][j] = _dependencyLabelProvider
.getText(_dsmContentProvider.getDependencies()[i][j]);
}
}
}
}
//
return _dependenciesAsStrings;
}
/**
* <p>
* Initializes the {@link DsmViewWidget}.
* </p>
*/
private void init() {
LightweightSystem lws = new LightweightSystem(this);
//
DsmViewWidgetMouseMotionListener motionListener = new DsmViewWidgetMouseMotionListener(this);
//
this.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseScrolled(org.eclipse.swt.events.MouseEvent e) {
if (e.count > 0) {
DsmViewWidget.this.setZoom(getZoom() * 1.05f);
} else if (e.count < 0) {
DsmViewWidget.this.setZoom(getZoom() * 0.95f);
}
}
});
//
// this.addMouseMoveListener(new MyMouseMoveListener(this));
_mainFigure = new Figure() {
@Override
public void paint(Graphics graphics) {
super.paint(graphics);
if (_drawToolTip && _x >= _verticalFigureWidth && _y >= _horizontalFigureHeight) {
graphics.fillRectangle(_x, _y, 100, 100);
graphics.drawRectangle(_x, _y, 100, 100);
}
}
};
_mainFigure.setLayoutManager(new XYLayout());
_mainFigure.addMouseMotionListener(motionListener);
lws.setContents(_mainFigure);
_colorScheme = new DefaultMatrixColorScheme();
_matrixFigure = new Matrix(_dsmContentProvider, _dependencyLabelProvider, _colorScheme);
_matrixFigure.addMouseMotionListener(motionListener);
_matrixFigure.addMouseListener(motionListener);
_zoomableScrollpane = new ZoomableScrollPane(_matrixFigure, ScrollPane.ALWAYS, ScrollPane.ALWAYS);
_verticalListFigure = new VerticalSideMarker(_dsmContentProvider, _artifactLabelProvider, _colorScheme);
_verticalListFigure.addMouseMotionListener(motionListener);
_zoomableScrollpaneVerticalBar = new ZoomableScrollPane(_verticalListFigure, ScrollPane.NEVER, ScrollPane.NEVER);
_horizontalListFigure = new HorizontalSideMarker(_dsmContentProvider, _artifactLabelProvider, _colorScheme);
_horizontalListFigure.addMouseMotionListener(motionListener);
_zoomableScrollpaneHorizontalBar = new ZoomableScrollPane(_horizontalListFigure, ScrollPane.NEVER, ScrollPane.NEVER);
_matrixFigure.addMouseMotionListener(new MouseMotionListener.Stub() {
/**
* {@inheritDoc}
*/
@Override
public void mouseExited(org.eclipse.draw2d.MouseEvent me) {
_drawToolTip = false;
}
});
_matrixFigure.addMatrixListener(new IMatrixListener() {
@Override
public void toolTip(MatrixEvent event) {
_drawToolTip = true;
_mainFigure.repaint();
}
@Override
public void singleClick(MatrixEvent event) {
_drawToolTip = false;
_mainFigure.repaint();
}
@Override
public void doubleClick(MatrixEvent event) {
_drawToolTip = false;
_mainFigure.repaint();
}
@Override
public void marked(MatrixEvent event) {
_mainFigure.repaint();
_horizontalListFigure.mark(event.getX());
_verticalListFigure.mark(event.getY());
}
});
// _zoomScrollBar = new ScrollBar();
// final Label zoomLabel = new Label("Zoom");
// zoomLabel.setBorder(new SchemeBorder(ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
// _zoomScrollBar.setThumb(zoomLabel);
// _zoomScrollBar.setHorizontal(true);
// _zoomScrollBar.setMaximum(200);
// _zoomScrollBar.setMinimum(0);
// _zoomScrollBar.setExtent(25);
// _zoomScrollBar.addPropertyChangeListener("value", new PropertyChangeListener() {
// @Override
// public void propertyChange(PropertyChangeEvent evt) {
// float z = (_zoomScrollBar.getValue() + 10) * 0.02f;
// _zoomableScrollpane.setZoom(z);
// _zoomableScrollpaneVerticalBar.setZoom(z);
// _zoomableScrollpaneHorizontalBar.setZoom(z);
// _zoom = z;
// }
// });
//
// _useShortendLabelsCheckBox = new CheckBox("Shorten labels");
// _useShortendLabelsCheckBox.getModel().addChangeListener(new ChangeListener() {
//
// @Override
// public void handleStateChanged(ChangeEvent event) {
// if ("selected".equals(event.getPropertyName())) {
// _model.setUseShortendLabels(_useShortendLabelsCheckBox.isSelected());
// _mainFigure.revalidate();
// _mainFigure.repaint();
// }
// }
// });
_zoomableScrollpane.getViewport().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Viewport viewport = (Viewport) evt.getSource();
_zoomableScrollpaneVerticalBar.getViewport().setViewLocation(0, viewport.getViewLocation().y);
_zoomableScrollpaneHorizontalBar.getViewport().setViewLocation(viewport.getViewLocation().x, 0);
// _zoomableScrollpaneHorizontalBar.getViewport().setViewLocation(0, 0);
_zoomableScrollpane.getViewport().setViewLocation(viewport.getViewLocation().x, viewport.getViewLocation().y);
_mainFigure.revalidate();
_mainFigure.repaint();
}
});
// _mainFigure.add(_zoomScrollBar);
// _mainFigure.add(_useShortendLabelsCheckBox);
_mainFigure.add(_zoomableScrollpane);
_mainFigure.add(_zoomableScrollpaneVerticalBar);
_mainFigure.add(_zoomableScrollpaneHorizontalBar);
_mainFigure.addLayoutListener(new LayoutListener.Stub() {
@Override
public boolean layout(IFigure container) {
layoutFigures(container);
return true;
}
});
}
/**
* <p>
* Compute the text extend.
* </p>
*
* @param matrixFigure
* @param zoomableScrollpane
* @return
*/
private int getTextExtend(final Matrix matrixFigure, final ZoomableScrollPane zoomableScrollpane) {
//
int testExtend = FigureUtilities.getTextWidth(DsmUtils.getLongestString(getNodesAsStrings()),
matrixFigure.getFont());
return (testExtend + 10/* * zoomableScrollpane.getZoom() */);
}
private void layoutFigures(IFigure figure) {
//
BoxSize boxSize = new BoxSize();
boxSize.setHorizontalBoxSize(computeSize());
//
_matrixFigure.setBoxSize(boxSize);
_horizontalListFigure.setBoxSize(boxSize);
_verticalListFigure.setBoxSize(boxSize);
// adjust size
_matrixFigure.resetSize();
_horizontalListFigure.resetSize();
_verticalListFigure.resetSize();
int horizontalBarHeight = (int) (_horizontalFigureHeight * _zoomableScrollpaneHorizontalBar.getZoom());
if (_verticalFigureWidth == -1) {
_verticalFigureWidth = getTextExtend(_matrixFigure, _zoomableScrollpane);
}
int verticalBarWidth = (int) (_verticalFigureWidth * _zoomableScrollpaneVerticalBar.getZoom());
//
_zoomableScrollpane.setLocation(new Point(verticalBarWidth, horizontalBarHeight));
_zoomableScrollpane.setSize(_mainFigure.getSize().width - verticalBarWidth,
(_mainFigure.getSize().height - (horizontalBarHeight)));
// HACK
int verticalOffset = 18;
_zoomableScrollpaneVerticalBar.setLocation(new Point(0, (/* HORIZONTAL_OFFSET + */horizontalBarHeight)));
_zoomableScrollpaneVerticalBar.setSize(verticalBarWidth,
(_mainFigure.getSize().height - (horizontalBarHeight + verticalOffset)));
//
_zoomableScrollpaneHorizontalBar.setLocation(new Point(verticalBarWidth, 0));
_zoomableScrollpaneHorizontalBar.setSize((_mainFigure.getSize().width - (verticalBarWidth + 18)),
horizontalBarHeight);
}
private int computeSize() {
String value = DsmUtils.getLongestString(getDependenciesAsStrings());
return FigureUtilities.getTextWidth(value, _matrixFigure.getFont()) + 6;
}
private final class DsmViewWidgetMouseMotionListener extends MouseMotionListener.Stub implements MouseListener {
/** - */
private final DsmViewWidget _dsmViewWidget;
/**
* <p>
* Creates a new instance of type {@link DsmViewWidgetMouseMotionListener}.
* </p>
*
* @param dsmViewWidget
*/
public DsmViewWidgetMouseMotionListener(DsmViewWidget dsmViewWidget) {
_dsmViewWidget = dsmViewWidget;
}
/** - */
private static final int HORIZONTAL = 1;
/** - */
private static final int VERTICAL = 2;
/** - */
private static final int DIAGONAL = 3;
/** - */
private static final int RANGE = 5;
/** - */
private int _currentDrag = -1;
/**
* {@inheritDoc}
*/
@Override
public void mousePressed(MouseEvent me) {
// //
// if (me.getSource().equals(_dsmViewWidget._matrixFigure)) {
// ((Figure) me.getSource()).setCursor(Cursors.HAND);
// }
}
/**
* {@inheritDoc}
*/
@Override
public void mouseReleased(MouseEvent me) {
// if (me.getSource().equals(_dsmViewWidget._matrixFigure)) {
// ((Figure) me.getSource()).setCursor(Cursors.ARROW);
// }
}
/**
* {@inheritDoc}
*/
@Override
public void mouseDoubleClicked(MouseEvent me) {
}
@Override
public void mouseMoved(MouseEvent me) {
handle(me, false);
}
@Override
public void mouseDragged(MouseEvent me) {
handle(me, true);
}
/**
* <p>
* </p>
*
* @param me
* @param isDragged
*/
private void handle(MouseEvent me, boolean isDragged) {
// if (!isDragged) {
// _currentDrag = -1;
// }
//
if (me.getSource() instanceof Figure && (me.getState() & SWT.BUTTON1) == 0) {
_currentDrag = isInRange(me);
switch (_currentDrag) {
case HORIZONTAL:
((Figure) me.getSource()).setCursor(Cursors.SIZENS);
break;
case VERTICAL:
((Figure) me.getSource()).setCursor(Cursors.SIZEWE);
break;
case DIAGONAL:
((Figure) me.getSource()).setCursor(Cursors.SIZENWSE);
break;
default:
((Figure) me.getSource()).setCursor(Cursors.ARROW);
break;
}
}
//
if ((me.getState() & SWT.BUTTON1) != 0 && isDragged) {
//
// if (_currentDrag == -1) {
// _currentDrag = isInRange(me);
// }
if ((me.getState() & SWT.SHIFT) != 0) {
//
if (me.getSource().equals(_dsmViewWidget._matrixFigure)) {
// float newZoom = me.getLocation().x / (float) _dsmViewWidget._verticalFigureWidth;
}
//
else if (me.getSource().equals(_dsmViewWidget._mainFigure)) {
float newZoom = me.getLocation().x / (float) _dsmViewWidget._verticalFigureWidth;
_dsmViewWidget.setZoom(newZoom);
}
} else {
//
if ((_currentDrag == HORIZONTAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._matrixFigure)) {
_dsmViewWidget._horizontalFigureHeight = _dsmViewWidget._horizontalFigureHeight + me.getLocation().y;
}
//
else if ((_currentDrag == HORIZONTAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._horizontalListFigure)) {
_dsmViewWidget._horizontalFigureHeight = me.getLocation().y;
}
//
else if ((_currentDrag == HORIZONTAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._verticalListFigure)) {
_dsmViewWidget._horizontalFigureHeight = _dsmViewWidget._horizontalFigureHeight + me.getLocation().y;
}
//
else if ((_currentDrag == HORIZONTAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._mainFigure)) {
_dsmViewWidget._horizontalFigureHeight = (int) ((me.getLocation().y / _dsmViewWidget._zoom));
}
//
if ((_currentDrag == VERTICAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._matrixFigure)) {
_dsmViewWidget._verticalFigureWidth = _dsmViewWidget._verticalFigureWidth + me.getLocation().x;
}
//
else if ((_currentDrag == VERTICAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._verticalListFigure)) {
_dsmViewWidget._verticalFigureWidth = me.getLocation().x;
}
//
else if ((_currentDrag == VERTICAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._horizontalListFigure)) {
_dsmViewWidget._verticalFigureWidth = _dsmViewWidget._verticalFigureWidth + me.getLocation().x;
}
//
else if ((_currentDrag == VERTICAL || _currentDrag == DIAGONAL)
&& me.getSource().equals(_dsmViewWidget._mainFigure)) {
_dsmViewWidget._verticalFigureWidth = (int) (me.getLocation().x / _dsmViewWidget._zoom);
}
}
_dsmViewWidget._mainFigure.revalidate();
}
}
/**
* <p>
* </p>
*
* @param me
* @return
*/
private int isInRange(MouseEvent me) {
//
if (me.getSource().equals(_dsmViewWidget._matrixFigure)) {
if (Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)
&& Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)) {
return DIAGONAL;
}
if (Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)) {
return VERTICAL;
}
if (Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)) {
return HORIZONTAL;
}
}
else if (me.getSource().equals(_dsmViewWidget._horizontalListFigure)) {
if (Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)
&& _dsmViewWidget._horizontalListFigure.getSize().height - Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)) {
return DIAGONAL;
}
if (Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)) {
return VERTICAL;
}
if (_dsmViewWidget._horizontalListFigure.getSize().height - Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)) {
return HORIZONTAL;
}
}
else if (me.getSource().equals(_dsmViewWidget._verticalListFigure)) {
if (Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)
&& _dsmViewWidget._verticalListFigure.getSize().width - Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)) {
return HORIZONTAL;
}
if (Math.abs(me.getLocation().y) < (RANGE * _dsmViewWidget._zoom)) {
return HORIZONTAL;
}
if (_dsmViewWidget._verticalListFigure.getSize().width - Math.abs(me.getLocation().x) < (RANGE * _dsmViewWidget._zoom)) {
return VERTICAL;
}
}
//
return -1;
}
}
}